package cn.le.io.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

/**
 *
 * SocketChanner的read()与write()操作与FileChannel类似,不同的是可以设置SocketChannel
 * 为非阻塞模式(non-blocking mode),设置后,就可以在异步模式下调用connect().read(),writer(),
 * 非阻塞模式与选择器搭配会工作的更好,通过将一或多个socketChannel注册到Selector,可以询问选择器
 * 那么通道已经备注好了读取,写入等,而ServerSocketChannel是一个可以监听新进来的tcp链接通道,
 * 就像标准io中的serverSocketChannel,通过调用open()方法打开,通过accept()方法监听新进来的链接.
 *
 *
 */
public class SocketChannelDemo {



}

/**
 * 服务器
 */
class Server{

    ServerSocketChannel serverSocketChannel;

    private void initServer(int port) throws IOException {

        serverSocketChannel = ServerSocketChannel.open();
        //绑定IP和端口
        serverSocketChannel.bind(new InetSocketAddress("127.0.0.1",port));
        //设置为非堵塞
        serverSocketChannel.configureBlocking(false);
        System.out.println("server初始化成功!");
    }

    /**
     * 监听链接
     * @throws IOException
     */
    private void listen() throws IOException {
        while (true)
        {
            //如果是阻塞模式程序会阻塞在这里,知道有链接进来
            //现在为非阻塞模式,无论有没有链接都会返回,socketChannel可能为null
            SocketChannel socketChannel  = serverSocketChannel.accept();
            if (socketChannel != null)
            {
                read(socketChannel);
            }
        }
    }
    private void read(SocketChannel socketChannel) throws IOException {
        ByteBuffer buf = ByteBuffer.allocate(1024);
        //非阻塞模式下read()方法可能尚未读取任何数据时就返回了,所以需要判断是否取到数据
        int index = socketChannel.read(buf);
        while( index != -1)
        {
            //转换为读模式
            buf.flip();
            System.out.println("收到消息"+ Charset.forName("utf-8").decode(buf));
            //清理数据,为写数据做准备
            buf.clear();
            index = socketChannel.read(buf);
        }
        System.out.println("index : "+index);
        ByteBuffer bf = ByteBuffer.wrap("你好呀,client,server收到你的消息!".getBytes(Charset.forName("UTF-8")));
        System.out.println(bf);
        socketChannel.write(bf);
    }

    public static void main(String[] args) throws IOException {

        Server server = new Server();
        server.initServer(8000);
        server.listen();
    }

}

/**
 * 客户端
 */
class Client{

    SocketChannel socketChannel;

    /**
     * 初始化
     * @param ip
     * @param port
     * @throws IOException
     */
    private void initClient(String ip,int port) throws IOException {
        socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(new InetSocketAddress(ip,port));
    }

    /**
     * 发送数据
     * @param msg
     * @throws IOException
     */
    private void sendMsg(String msg) throws IOException {
        ByteBuffer buf = ByteBuffer.wrap(msg.getBytes(Charset.forName("utf-8")));
        socketChannel.write(buf);
    }

    public static void main(String[] args) throws IOException {

        Client client = new Client();
        client.initClient("127.0.0.1",8000);
        //验证完成套接字通道的连接过程
        while (!client.socketChannel.finishConnect())
        {
            System.out.println("等待链接...");
        }
        client.sendMsg("今晚暗号");
        client.sendMsg("天王盖地虎");
        client.sendMsg("宝塔镇河妖");

        client.read();

        //客户端需要关闭通道,不然服务器会出现:远程主机强迫关闭了一个现有的连接
        client.close();

    }
    private  void  close() throws IOException {
        socketChannel.close();
    }
    private void read() throws IOException {
        ByteBuffer buf = ByteBuffer.allocate(1024);

        //非阻塞模式下read()方法可能尚未读取任何数据时就返回了,所以需要判断是否取到数据
        int index = socketChannel.read(buf);
        while(index != -1)
        {
            //转换为读模式
            buf.flip();
            System.out.println("收到消息"+ Charset.forName("utf-8").decode(buf));
            //清理数据,为写数据做准备
            index = socketChannel.read(buf);
            System.out.println("index : "+index);
            buf.clear();
        }

    }

}
















